<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>this指向说明(This points to the explanation)</title>
  <!-- 
  `this`  是 JavaScript 中一个重要的概念，它的值在不同的上下文中会有所不同。
  1. 全局上下文中的  `this` 
  - 概念：在全局上下文中（非函数内部）， `this`  指向全局对象。在浏览器中， `this`  指向  `window`  对象。
    console.log(this); // 在浏览器中输出: Window { ... }

  - 总结：在全局作用域中， `this`  指向全局对象。

  2. 函数上下文中的  `this` 
  - 概念：在普通函数中， `this`  的值取决于函数的调用方式。
    function showThis() {
      console.log(this);
    }

    showThis(); // 输出: Window { ... } (在浏览器中)

  - 总结：在普通函数中， `this`  默认指向全局对象（在严格模式下为  `undefined` ）。

  3. 对象方法中的  `this` 
  - 概念：当  `this`  在对象的方法中被调用时，它指向调用该方法的对象。
    const person = {
      name: '张三',
      greet: function() {
        console.log('你好, ' + this.name);
      }
    };

    person.greet(); // 输出: 你好, 张三

  - 总结：在对象的方法中， `this`  指向调用该方法的对象。

  4. 构造函数中的  `this` 
  - 概念：在构造函数中， `this`  指向新创建的对象实例。
    function Person(name) {
      this.name = name;
    }

    const person1 = new Person('李四');
    console.log(person1.name); // 输出: 李四

  - 总结：在构造函数中， `this`  指向新创建的对象实例。

  5. 事件处理中的  `this` 
  - 概念：在事件处理函数中， `this`  指向触发事件的元素。
    <button id="myButton">点击我</button>
    <script>
      document.getElementById('myButton').addEventListener('click', function() {
        console.log(this); // 输出: <button id="myButton">点击我</button>
      });
    </script>

  - 总结：在事件处理函数中， `this`  指向触发事件的 DOM 元素。

  6. 使用  `call` 、 `apply`  和  `bind`  方法
  - 概念：使用  `call` 、 `apply`  和  `bind`  方法可以显式地指定  `this`  的值。
    function greet() {
      console.log('你好, ' + this.name);
    }

    const person = { name: '王五' };
    greet.call(person); // 输出: 你好, 王五

  - 总结：通过  `call` 、 `apply`  和  `bind` ，可以灵活地控制  `this`  的指向。

  总结
  `this`  是 JavaScript 中一个复杂但重要的概念。理解  `this`  的指向对于编写正确和高效的 JavaScript 代码至关重要。通过不同的上下文和调用方式， `this`  的值会有所变化，开发者需要根据具体情况灵活使用。
   -->
</head>
<body>

  <button id="myButton">this指向说明按钮</button>

  <script>

    // 1. 全局上下文中的 this - 普通的函数被默认调用, 那么this指向的就是window 对象 (在浏览器中) 或 global 对象 (在 Node.js 中) 严格模式下为 undefined
    // 输出: window 对象 (在浏览器中) 或 global 对象 (在 Node.js 中) 严格模式下为 undefined
    console.log("1. 全局上下文中的", this); 

    // 2. 函数上下文中的  this 函数中是有一个this的变量, this变量在大多数情况下会指向一个对象, 这个对象被称为函数的调用者(函数它是被某一个对象来引用并且调用它, 那么this会指向这个对象)
    function foo() {
      // 输出: window 对象 (在浏览器中) 或 global 对象 (在 Node.js 中)
      console.log("2. 函数上下文中的", this); 
    }
    foo();

    // 3. 对象方法中的 this - 对象方法中的this指向的是调用这个方法的对象
    const obj = {
      name: '张三',
      greet: function() {
        console.log('3. 对象方法中的: ' + this.name);
      }
    };
    obj.greet(); // 输出: 3. 对象方法中的: 张三

    // 4. 构造函数中的 this - 函数在new操作符调用时, this指向的是新创建的对象
    function Person(name) {
      this.name = name;
      this.greet = function() {
        console.log('4. 构造函数中的, ' + this.name);
      };
    }
    const person = new Person('李四');
    person.greet(); // 输出: 4. 构造函数中的, 李四

    // 5. 事件处理函数中的 this - 事件处理函数中的this指向的是触发事件的元素
    document.getElementById('myButton').addEventListener('click', function() {
      console.log("5. 事件处理函数中的", this); // 输出: 被点击的按钮元素
    });

    // 6. 箭头函数中的 this - 箭头函数没有自己的this, 它会捕获其所在上下文的this值
    const obj2 = {
      name: '王五',
      friend: {
        age: '赵六',
        greet: function() {
          console.log('6.1 函数中的: ' + this.name, this.age);
        },
        greet2: () => {
          console.log('6.2 箭头函数中的: ' + this.name, this.age);
        }
      },
      greet: function() {
        const arrowFunction = () => {
          console.log('6.3 箭头函数中的: ' + this.name);
        };
        arrowFunction();
      }
    }

    obj2.friend.greet(); // 输出: 6.1 函数中的: undefined 赵六
    obj2.friend.greet2(); // 输出: 6.2 箭头函数中的: undefined
    obj2.greet(); // 输出: 6.3 箭头函数中的: 王五
    
    // 7. 立即执行函数中的 this - 立即执行函数中的this指向的是全局对象
    (function() {
      console.log('7. 立即执行函数中的', this); // 输出: 全局对象
    })();

    // 8. this 考题
    // 8,1
    let fn = obj2.friend.greet;
    fn() // undefined

    // 8.2
    function bar() {
      console.log('8.2 函数中的', this);
    }
    const objBar = {
      name: '张三',
      bar: bar
    }

    objBar.bar() // 输出: 8.2 函数中的 { name: '张三', bar: [Function: bar] }
    bar() // 输出: 8.2 函数中的 全局对象 windeow

    // 8.3
    const objBar2 = {
      name: '张三',
      bar: function() {
        console.log('8.3 函数中的', this);
      }
    }

    objBar2.bar() // 输出: 8.3 函数中的 { name: '张三', bar: [Function: bar] }
   
   
    
  </script>
  
</body>
</html>